package com.cyru.statemachine.core.impl;

import com.cyru.statemachine.Visitor;
import com.cyru.statemachine.core.State;
import com.cyru.statemachine.core.Transition;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * description:
 *
 * @author zhangxuchuan
 * date 2022/5/2
 */
public class DefaultState<S, E, C> implements State<S, E, C> {

    private final S id;

    /**
     * 当前状态对应的转换集合
     */
    private final Map<E, List<Transition<S, E, C>>> transitionMap = new HashMap<>();


    public DefaultState(S id) {
        this.id = id;
    }

    @Override
    public S getId() {
        return id;
    }

    @Override
    public Transition<S, E, C> addTransition(State<S, E, C> target, E event) {
        Transition<S, E, C> transition = new TransitionImpl<>();
        DefaultTrigger<S, E, C> trigger = new DefaultTrigger<>();
        trigger.setEvent(event);
        transition.setTrigger(trigger);
        transition.setSourceState(this);
        transition.setTargetState(target);
        transitionMap.computeIfAbsent(event, e -> new ArrayList<>()).add(transition);
        return transition;
    }

    @Override
    public List<Transition<S, E, C>> getTransitionByEvent(E event) {
        return transitionMap.get(event);
    }

    @Override
    public List<Transition<S, E, C>> getAllTransition() {
        return transitionMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(id);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        DefaultState<?, ?, ?> that = (DefaultState<?, ?, ?>) obj;
        return Objects.equals(that.id, obj);
    }

    @Override
    public String accept(Visitor visitor) {
        return visitor.visitState(this);
    }
}
